/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools mkfs check point writer
 */

#include "check_point_writer.h"

#include <cinttypes>
#include <random>
#include <string>
#include <sys/types.h>

#include "device_manager.h"
#include "hmfs_common.h"
#include "hmfs_io.h"
#include "hmfs_log.h"
#include "hmfs_quota.h"
#include "hmfs_zoned.h"
#include "mkfs_format.h"
#include "securec.h"

namespace OHOS {
namespace Hmfs {
CheckPointWriter::CheckPointWriter(MkfsFormat &mkfs) : mkfs_(mkfs) {}

int32_t CheckPointWriter::Format()
{
    HmfsData &hmfsData = mkfs_.hmfsData_;

    if (PrepareCheckPointData() != 0) {
        return -1;
    }

    writeBlockId_ = hmfsData.segment0BlockId;
    MakeCheckPointCrc();
    if (WriteCpStruct() != 0) {
        return -1;
    }

    if (PrepareEmptyBlock() != 0) {
        return -1;
    }

    if (WriteCpPayload() != 0) {
        return -1;
    }

    if (PrepareActiveSegments() != 0) {
        return -1;
    }

    if (PrepareNodeSummary() != 0) {
        return -1;
    }

    if (WriteActiveSegments() != 0) {
        return -1;
    }

    if (WriteCpStruct() != 0) {
        return -1;
    }

#ifndef HMFS_TOOLS_ARM64
    if (PrepareNatBit() != 0) {
        return -1;
    }

    if (WriteNatBit() != 0) {
        return -1;
    }
#endif

    // second segment
    CheckPointData *checkPoint = &checkPoint_->cp;
    checkPoint->checkPointVersion = 0;
    MakeCheckPointCrc();
    writeBlockId_ = hmfsData.segment0BlockId + BLOCKS_PER_SEGMENT;
    if (WriteCpStruct() != 0) {
        return -1;
    }

    if (WriteCpPayload() != 0) {
        return -1;
    }

    writeBlockId_ += 4; // 4 is data summaries (1) + node summaries (3)
    if (WriteCpStruct() != 0) {
        return -1;
    }

    return 0;
}

int32_t CheckPointWriter::PrepareCheckPointDataEnd(CheckPointData *checkPoint)
{
    if (checkPoint == nullptr) {
        return -1;
    }
    CmdConfig &cfgPara = mkfs_.cfgPara_;
    HmfsData &hmfsData = mkfs_.hmfsData_;
    uint32_t flags = CP_FLAG_UMOUNT | CP_FLAG_COMPACT_SUM;
#ifndef HMFS_TOOLS_ARM64
    if (GetLeValue(checkPoint->checkPointPackBlockCount) <= BLOCKS_PER_SEGMENT - natBitsAreablocks_) {
        flags |= CP_FLAG_NAT_BITS;
    }
#endif
    if (cfgPara.trim) {
        flags |= CP_FLAG_TRIMMED;
    }

    if (cfgPara.largeNatBitmap) {
        flags |= CP_FLAG_LARGE_NAT_BITMAP;
    }

    SetLeValue(checkPoint->checkPointFlags, flags);
    SetLeValue(checkPoint->summaryStartBlock, 1 + hmfsData.checkPointPayload);
    SetLeValue(checkPoint->validNodeCount, 1 + hmfsData.quotaInodeCount + hmfsData.lpfInodeCount);
    SetLeValue(checkPoint->validInodeCount, 1 + hmfsData.quotaInodeCount + hmfsData.lpfInodeCount);
    SetLeValue(checkPoint->nextFreeNodeId, hmfsData.nextFreeInodeId);
    SetLeValue(checkPoint->sitVersionBitmapSize,
        (hmfsData.segmentCountInSIT / HMFS_SIT_COUNT) * BLOCKS_PER_SEGMENT / BITS_PER_BYTE);
    SetLeValue(checkPoint->natVersionBitmapSize,
        (hmfsData.segmentCountInNAT / HMFS_NAT_COUNT) * BLOCKS_PER_SEGMENT / BITS_PER_BYTE);

    std::mt19937 generator(cfgPara.fakeSeed ? 0 : std::random_device{}());
    std::uniform_int_distribution<uint32_t> distribution(1, UINT32_MAX);
    SetLeValue(checkPoint->checkPointVersion, distribution(generator));
    HMFS_DEBUG("checkPoint->checkPointVersion = %" PRIx64 "", checkPoint->checkPointVersion);

    return 0;
}

int32_t CheckPointWriter::PrepareCheckPointData()
{
    CmdConfig &cfgPara = mkfs_.cfgPara_;
    HmfsData &hmfsData = mkfs_.hmfsData_;

    checkPoint_ = std::make_unique<CheckPointOnDisk>();
    auto result = memset_s(checkPoint_.get(), sizeof(CheckPointOnDisk), 0, sizeof(CheckPointOnDisk));
    HMFS_CHECK(result == EOK, return -1, "Failed to memset CheckPointOnDisk");
    CheckPointData *checkPoint = &checkPoint_->cp;

    uint32_t segNo = 0;
    SetLeValue(checkPoint->curNodeSegNo[segNo], hmfsData.currentSegments[CURSEG_NODE_HOT]);
    SetLeValue(checkPoint->curDataSegNo[segNo++], hmfsData.currentSegments[CURSEG_DATA_HOT]);
    SetLeValue(checkPoint->curNodeSegNo[segNo], hmfsData.currentSegments[CURSEG_NODE_WARM]);
    SetLeValue(checkPoint->curDataSegNo[segNo++], hmfsData.currentSegments[CURSEG_DATA_WARM]);
    SetLeValue(checkPoint->curNodeSegNo[segNo], hmfsData.currentSegments[CURSEG_NODE_COLD]);
    SetLeValue(checkPoint->curDataSegNo[segNo++], hmfsData.currentSegments[CURSEG_DATA_COLD]);
    for (; segNo < HMFS_MAX_ACTIVE_NODE_LOGS; segNo++) {
        SetLeValue(checkPoint->curNodeSegNo[segNo], 0xffffffff);
        SetLeValue(checkPoint->curDataSegNo[segNo], 0xffffffff);
    }

    uint64_t usedNodeBlocks = 1 + hmfsData.quotaInodeCount + hmfsData.lpfInodeCount;
    uint64_t usedDataBlocks = 1 + hmfsData.quotaDataBlks + hmfsData.lpfDataBlks;
    SetLeValue(checkPoint->curNodeBlkOffset[0], usedNodeBlocks);
    SetLeValue(checkPoint->curDataBlkOffset[0], usedDataBlocks);
    SetLeValue(checkPoint->validBlockCount, usedNodeBlocks + usedDataBlocks);
    SetLeValue(checkPoint->reservedSegmentCount, hmfsData.reservedSegments);

    SuperBlockData *superBlock = mkfs_.GetSuperBlockData();
    HMFS_ASSERT(superBlock != nullptr);
    uint32_t usableSegments = HmfsZoned::GetInstance().HmfsGetUsableSegments(superBlock);
    uint32_t overprovisionSegmentCount = (usableSegments - hmfsData.reservedSegments) *
        cfgPara.overProvision / PERCENT_TIMES + hmfsData.reservedSegments;
    SetLeValue(checkPoint->overprovisionSegmentCount, overprovisionSegmentCount);

    if (usableSegments <= overprovisionSegmentCount) {
        HMFS_ERROR("Not enough segments to create HMFS Volume\n");
        return -1;
    }
    HMFS_INFO("Overprovision ratio = %.3lf%%", cfgPara.overProvision);
    HMFS_INFO("Overprovision segments = %u (GC reserved = %u)", overprovisionSegmentCount, hmfsData.reservedSegments);

    uint32_t freeSegmentCount = usableSegments -
        ((cfgPara.features & HMFS_FEATURE_RO) ? HMFS_META_SEGMENTS_RO : HMFS_META_SEGMENTS);
    SetLeValue(checkPoint->freeSegmentCount, freeSegmentCount);
    SetLeValue(checkPoint->userBlockCount, (usableSegments - overprovisionSegmentCount) * BLOCKS_PER_SEGMENT);

    /* 6 is cp page (2) + data summaries (1) + node summaries (3) */
    SetLeValue(checkPoint->checkPointPackBlockCount, 6 + hmfsData.checkPointPayload);

    natBitmapSize_ = (hmfsData.segmentCountInNAT / HMFS_NAT_COUNT) * BLOCKS_PER_SEGMENT / BITS_PER_BYTE;
    natBitsAreablocks_ = AlignUpCount(sizeof(uint64_t) + natBitmapSize_ + natBitmapSize_, HMFS_BLOCK_SIZE);

    return PrepareCheckPointDataEnd(checkPoint);
}

void CheckPointWriter::MakeCheckPointCrc()
{
    CmdConfig &cfgPara = mkfs_.cfgPara_;
    CheckPointData *checkPoint = &checkPoint_->cp;
    uint32_t checksumOffset = cfgPara.largeNatBitmap ? CP_MIN_CHECKSUM_OFFSET : CP_CHECKSUM_OFFSET;
    SetLeValue(checkPoint->checksumOffset, checksumOffset);

    uint32_t crc = HmfsCommon::GetInstance().GetCheckpointChksum(checkPoint);
    HMFS_DEBUG("CP crc = 0x%x", crc);
    uint32_t *crcAddr = reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(checkPoint) + checksumOffset);
    SetLeValue(*crcAddr, crc);
}

int32_t CheckPointWriter::PrepareActiveSegments()
{
    HmfsData &hmfsData = mkfs_.hmfsData_;
    CmdConfig &cfgPara = mkfs_.cfgPara_;

    activeSegments_ = std::make_unique<uint8_t[]>(HMFS_BLOCK_SIZE);
    auto result = memset_s(activeSegments_.get(), HMFS_BLOCK_SIZE, 0, HMFS_BLOCK_SIZE);
    HMFS_CHECK(result == EOK, return -1, "Failed to memset activeSegments");
    JournalEntry *natJournal = reinterpret_cast<JournalEntry *>(activeSegments_.get());
    if (FillNatJournal(natJournal) != 0) {
        return -1;
    }

    JournalEntry *sitJournal = natJournal + 1;
    FillSitJournal(sitJournal);

    SummaryEntry *sumEntry = reinterpret_cast<SummaryEntry *>(sitJournal + 1);
    SetLeValue(sumEntry->nodeId, hmfsData.rootInode);
    sumEntry->nodeBlockOffset = 0;

    SuperBlockData *superBlock = mkfs_.GetSuperBlockData();
    if (superBlock == nullptr) {
        return -1;
    }

    uint32_t offset = 1;
    for (int32_t qtype = 0; qtype < MAX_QUOTAS; qtype++) {
        if (!((1 << qtype) & cfgPara.quotaBits)) {
            continue;
        }

        for (int32_t i = 0; i < QUOTA_DATA_BLOCK_COUNT; i++) {
            (sumEntry + offset + i)->nodeId = superBlock->quotaInodeId[qtype];
            (sumEntry + offset + i)->nodeBlockOffset = NativeToLE16(i);
        }
        offset += QUOTA_DATA_BLOCK_COUNT;
    }

    if (hmfsData.lpfDataBlks) {
        (sumEntry + offset)->nodeId = NativeToLE32(hmfsData.lpfInodeId);
        (sumEntry + offset)->nodeBlockOffset = 0;
    }

    return 0;
}

int32_t CheckPointWriter::FillNatJournal(JournalEntry *natJournal)
{
    HmfsData &hmfsData = mkfs_.hmfsData_;
    CmdConfig &cfgPara = mkfs_.cfgPara_;
    CheckPointData *checkPoint = &checkPoint_->cp;

    uint32_t entryIndex = 0;
    SetLeValue(natJournal->natCount, 1 + hmfsData.quotaInodeCount + hmfsData.lpfInodeCount);
    SetLeValue(natJournal->natJournalArray.entries[entryIndex].nodeId, hmfsData.rootInode);
    natJournal->natJournalArray.entries[entryIndex].natEntry.version = 0;
    natJournal->natJournalArray.entries[entryIndex].natEntry.inodeNumber =
        natJournal->natJournalArray.entries[entryIndex].nodeId;
    SetLeValue(natJournal->natJournalArray.entries[entryIndex].natEntry.blockId,
        hmfsData.mainStartBlkId + hmfsData.currentSegments[CURSEG_NODE_HOT] * BLOCKS_PER_SEGMENT);
    entryIndex++;

    SuperBlockData *superBlock = mkfs_.GetSuperBlockData();
    if (superBlock == nullptr) {
        return -1;
    }

    for (int32_t qtype = 0; qtype < MAX_QUOTAS; qtype++) {
        if (!((1 << qtype) & cfgPara.quotaBits)) {
            continue;
        }

        natJournal->natJournalArray.entries[entryIndex].nodeId = superBlock->quotaInodeId[qtype];
        natJournal->natJournalArray.entries[entryIndex].natEntry.version = 0;
        natJournal->natJournalArray.entries[entryIndex].natEntry.inodeNumber = superBlock->quotaInodeId[qtype];
        SetLeValue(natJournal->natJournalArray.entries[entryIndex].natEntry.blockId,
            hmfsData.mainStartBlkId + checkPoint->curNodeSegNo[0] * BLOCKS_PER_SEGMENT + entryIndex);
        entryIndex++;
    }

    if (hmfsData.lpfInodeCount) {
        natJournal->natJournalArray.entries[entryIndex].nodeId = NativeToLE32(hmfsData.lpfInodeId);
        natJournal->natJournalArray.entries[entryIndex].natEntry.version = 0;
        natJournal->natJournalArray.entries[entryIndex].natEntry.inodeNumber = NativeToLE32(hmfsData.lpfInodeId);
        SetLeValue(natJournal->natJournalArray.entries[entryIndex].natEntry.blockId,
            hmfsData.mainStartBlkId + checkPoint->curNodeSegNo[0] * BLOCKS_PER_SEGMENT + entryIndex);
    }

    return 0;
}

void CheckPointWriter::FillSitJournal(JournalEntry *sitJournal)
{
    HmfsData &hmfsData = mkfs_.hmfsData_;
    CmdConfig &cfgPara = mkfs_.cfgPara_;
    CheckPointData *checkPoint = &checkPoint_->cp;

    uint32_t entryIndex = 0;
    SetLeValue(sitJournal->sitCount, (cfgPara.features & HMFS_FEATURE_RO) ? HMFS_META_SEGMENTS_RO : HMFS_META_SEGMENTS);
    sitJournal->sitJournalArray.entries[entryIndex].sitNumber = checkPoint->curNodeSegNo[entryIndex];
    SetLeValue(sitJournal->sitJournalArray.entries[entryIndex].sitEntry.usedBlocks,
        (CURSEG_NODE_HOT << SIT_USER_BLOCK_COUNT_SHIFT) | (1 + hmfsData.quotaInodeCount + hmfsData.lpfInodeCount));

    uint32_t bitId = 0;
    HmfsCommon::GetInstance().SetBit(bitId++, sitJournal->sitJournalArray.entries[entryIndex].sitEntry.blockBitmap);
    for (uint32_t i = 0; i < hmfsData.quotaInodeCount; i++) {
        HmfsCommon::GetInstance().SetBit(bitId++, sitJournal->sitJournalArray.entries[entryIndex].sitEntry.blockBitmap);
    }
    if (hmfsData.lpfInodeCount) {
        HmfsCommon::GetInstance().SetBit(bitId, sitJournal->sitJournalArray.entries[entryIndex].sitEntry.blockBitmap);
    }
    entryIndex++;

    if ((cfgPara.features & HMFS_FEATURE_RO) == 0) {
        sitJournal->sitJournalArray.entries[entryIndex].sitNumber = checkPoint->curNodeSegNo[entryIndex];
        SetLeValue(sitJournal->sitJournalArray.entries[entryIndex].sitEntry.usedBlocks,
            CURSEG_NODE_WARM << SIT_USER_BLOCK_COUNT_SHIFT);
        entryIndex++;

        sitJournal->sitJournalArray.entries[entryIndex].sitNumber = checkPoint->curNodeSegNo[entryIndex];
        SetLeValue(sitJournal->sitJournalArray.entries[entryIndex].sitEntry.usedBlocks,
            CURSEG_NODE_COLD << SIT_USER_BLOCK_COUNT_SHIFT);
        entryIndex++;
    }

    FillSitJournalSegData(sitJournal, entryIndex);
}

void CheckPointWriter::FillSitJournalSegData(JournalEntry *sitJournal, uint32_t entryIndex)
{
    HmfsData &hmfsData = mkfs_.hmfsData_;
    CmdConfig &cfgPara = mkfs_.cfgPara_;
    CheckPointData *checkPoint = &checkPoint_->cp;

    uint32_t dataSegIndex = 0;
    sitJournal->sitJournalArray.entries[entryIndex].sitNumber = checkPoint->curDataSegNo[dataSegIndex];
    SetLeValue(sitJournal->sitJournalArray.entries[entryIndex].sitEntry.usedBlocks,
        (CURSEG_DATA_HOT << SIT_USER_BLOCK_COUNT_SHIFT) | (1 + hmfsData.quotaDataBlks + hmfsData.lpfDataBlks));
    uint32_t bitId = 0;
    HmfsCommon::GetInstance().SetBit(bitId++, sitJournal->sitJournalArray.entries[entryIndex].sitEntry.blockBitmap);
    for (uint32_t i = 0; i < hmfsData.quotaDataBlks; i++) {
        HmfsCommon::GetInstance().SetBit(bitId++,
            sitJournal->sitJournalArray.entries[entryIndex].sitEntry.blockBitmap);
    }
    if (hmfsData.lpfDataBlks) {
        HmfsCommon::GetInstance().SetBit(bitId,
            sitJournal->sitJournalArray.entries[entryIndex].sitEntry.blockBitmap);
    }
    entryIndex++;
    dataSegIndex++;

    if ((cfgPara.features & HMFS_FEATURE_RO) == 0) {
        sitJournal->sitJournalArray.entries[entryIndex].sitNumber = checkPoint->curDataSegNo[dataSegIndex];
        SetLeValue(sitJournal->sitJournalArray.entries[entryIndex].sitEntry.usedBlocks,
            CURSEG_DATA_WARM << SIT_USER_BLOCK_COUNT_SHIFT);
        entryIndex++;
        dataSegIndex++;

        sitJournal->sitJournalArray.entries[entryIndex].sitNumber = checkPoint->curDataSegNo[dataSegIndex];
        SetLeValue(sitJournal->sitJournalArray.entries[entryIndex].sitEntry.usedBlocks,
            CURSEG_DATA_COLD << SIT_USER_BLOCK_COUNT_SHIFT);
    }
}

int32_t CheckPointWriter::PrepareNodeSummary()
{
    CmdConfig &cfgPara = mkfs_.cfgPara_;
    HmfsData &hmfsData = mkfs_.hmfsData_;
    SuperBlockData *superBlock = mkfs_.GetSuperBlockData();
    if (superBlock == nullptr) {
        return -1;
    }

    hotNodeSumary_ = std::make_unique<SummaryBlockData>();
    auto result = memset_s(hotNodeSumary_.get(), sizeof(SummaryBlockData), 0, sizeof(SummaryBlockData));
    HMFS_CHECK(result == EOK, return -1, "Failed to memset hotNodeSumary");

    hotNodeSumary_->footer.entryType = 1;

    uint32_t id = 0;
    SetLeValue(hotNodeSumary_->entries[id].nodeId, hmfsData.rootInode);
    hotNodeSumary_->entries[id++].nodeBlockOffset = 0;
    for (int32_t qtype = 0; qtype < MAX_QUOTAS; qtype++) {
        if (!((1 << qtype) & cfgPara.quotaBits)) {
            continue;
        }

        hotNodeSumary_->entries[id].nodeId = superBlock->quotaInodeId[qtype];
        hotNodeSumary_->entries[id++].nodeBlockOffset = 0;
    }
    if (hmfsData.lpfInodeCount) {
        hotNodeSumary_->entries[id].nodeId = NativeToLE32(hmfsData.lpfInodeId);
        hotNodeSumary_->entries[id].nodeBlockOffset = 0;
    }

    warmColdNodeSumary_ = std::make_unique<SummaryBlockData>();
    result = memset_s(warmColdNodeSumary_.get(), sizeof(SummaryBlockData), 0, sizeof(SummaryBlockData));
    HMFS_CHECK(result == EOK, return -1, "Failed to memset warmColdNodeSumary");

    warmColdNodeSumary_->footer.entryType = 1;

    return 0;
}

int32_t CheckPointWriter::PrepareNatBit()
{
#ifndef HMFS_TOOLS_ARM64
    CheckPointData *checkPoint = &checkPoint_->cp;

    if (!(GetLeValue(checkPoint->checkPointFlags) & CP_FLAG_NAT_BITS)) {
        return 0;
    }

    /* +---------+------------------+-------------------+
     * | crc     | full nat bit map | empty nat bit map |
     * +---------+------------------+-------------------+
     *  uint64_t    natBitmapSize_     natBitmapSize_
     *                 all zero
     */
    uint32_t natBitAreaSize = HMFS_BLOCK_SIZE * natBitsAreablocks_;
    natBits_ = std::make_unique<uint8_t[]>(natBitAreaSize);
    auto result = memset_s(natBits_.get(), natBitAreaSize, 0, natBitAreaSize);
    HMFS_CHECK(result == EOK, return -1, "Failed to memset natBits");

    uint64_t *crc = reinterpret_cast<uint64_t *>(natBits_.get());
    *crc = HmfsCommon::GetInstance().GetCpCrc(checkPoint);

    uint8_t *emptyNatBitmap = natBits_.get() + sizeof(uint64_t) + natBitmapSize_;
    result = memset_s(emptyNatBitmap, natBitmapSize_, 0xff, natBitmapSize_);
    HMFS_CHECK(result == EOK, return -1, "Failed to memset emptyNatBitmap");
    HmfsCommon::GetInstance().TestAndClearBitLe(0, emptyNatBitmap);
#endif

    return 0;
}

int32_t CheckPointWriter::PrepareEmptyBlock()
{
    emptyBlock_ = std::make_unique<uint8_t[]>(HMFS_BLOCK_SIZE);
    auto result = memset_s(emptyBlock_.get(), HMFS_BLOCK_SIZE, 0, HMFS_BLOCK_SIZE);
    HMFS_CHECK(result == EOK, return -1, "Failed to memset emptyBlock");
    return 0;
}

int32_t CheckPointWriter::WriteCpStruct()
{
    HMFS_DEBUG("Writing cp data at blockid 0x%" PRIx64 "", writeBlockId_);
    if (HmfsIo::GetInstance().DevWriteBlock(checkPoint_.get(), writeBlockId_)) {
        HMFS_ERROR("failed to write the cp to disk");
        return -1;
    }
    writeBlockId_++;

    return 0;
}

int32_t CheckPointWriter::WriteCpPayload()
{
    HmfsData &hmfsData = mkfs_.hmfsData_;

    for (uint32_t i = 0; i < hmfsData.checkPointPayload; i++) {
        HMFS_DEBUG("Writing cp payload at blockid 0x%" PRIx64 "", writeBlockId_);
        if (HmfsIo::GetInstance().DevFillBlock(emptyBlock_.get(), writeBlockId_)) {
            HMFS_ERROR("failed to write the sit bitmap area to disk");
            return -1;
        }
        writeBlockId_++;
    }

    return 0;
}

int32_t CheckPointWriter::WriteActiveSegments()
{
    HMFS_DEBUG("Writing Segment summary for HOT/WARM/COLD_DATA at blockid 0x%" PRIx64 "", writeBlockId_);
    if (HmfsIo::GetInstance().DevWriteBlock(activeSegments_.get(), writeBlockId_)) {
        HMFS_ERROR("failed to write the activeSegments to disk, blockid = %" PRIu64 "", writeBlockId_);
        return -1;
    }
    writeBlockId_++;

    // hot node summary
    HMFS_DEBUG("Writing Segment summary for HOT_NODE at blockid 0x%" PRIx64 "", writeBlockId_);
    if (HmfsIo::GetInstance().DevWriteBlock(hotNodeSumary_.get(), writeBlockId_)) {
        HMFS_ERROR("failed to write the hot Node Sumary to disk, blockid = %" PRIu64 "", writeBlockId_);
        return -1;
    }
    writeBlockId_++;

    // warm node summary
    HMFS_DEBUG("Writing Segment summary for WARM_NODE at blockid 0x%" PRIx64 "", writeBlockId_);
    if (HmfsIo::GetInstance().DevWriteBlock(warmColdNodeSumary_.get(), writeBlockId_)) {
        HMFS_ERROR("failed to write the warm node summary to disk, blockid = %" PRIu64 "", writeBlockId_);
        return -1;
    }
    writeBlockId_++;

    // cold node summary
    HMFS_DEBUG("Writing Segment summary for COLD_NODE at blockid 0x%" PRIx64 "", writeBlockId_);
    if (HmfsIo::GetInstance().DevWriteBlock(warmColdNodeSumary_.get(), writeBlockId_)) {
        HMFS_ERROR("failed to write the cold node summary to disk, blockid = %" PRIu64 "", writeBlockId_);
        return -1;
    }
    writeBlockId_++;

    return 0;
}

int32_t CheckPointWriter::WriteNatBit()
{
    HmfsData &hmfsData = mkfs_.hmfsData_;

    writeBlockId_ = hmfsData.segment0BlockId + BLOCKS_PER_SEGMENT - natBitsAreablocks_;
    HMFS_DEBUG("Writing NAT bits at blockid 0x%" PRIx64 ", count %u", writeBlockId_, natBitsAreablocks_);
    for (uint32_t i = 0; i < natBitsAreablocks_; i++) {
        if (HmfsIo::GetInstance().DevWriteBlock(natBits_.get() + i * HMFS_BLOCK_SIZE, writeBlockId_)) {
            HMFS_ERROR("failed to write NAT bits!\n");
            return -1;
        }
        writeBlockId_++;
    }
    return 0;
}

} // namespace Hmfs
} // namespace OHOS
